#pragma once
#include "InetAddr.hpp"
#include "Log.hpp"
#include "Socket.hpp"

using namespace LogModule;
using namespace InetAddrModule;
using namespace SocketModule;

const int NUM = sizeof(fd_set) * 8 + 1;
const int gdefaultfd = -1;
class SelectSever
{
private:
    void Accepter()
    {
        InetAddr peer;
        int newfd = _listen_socketfd->Accepter(&peer);
        if(newfd < 0)
            return;
        
        LOG(LogLevel::DEBUG) << "获得一个新连接：" << peer.Addr();

        int pos = -1;
        for(int i = 0;i < NUM;i++)
        {
            if(_fd_array[i] == gdefaultfd)
            {
                pos = i;
                break;
            }
        }
        if(pos == -1)
        {
            LOG(LogLevel::WARNING) << "服务器已达到最大连接数";
            close(newfd);
        }
        else
        {
            _fd_array[pos] = newfd;
        }
    }
    void Recver(int who)
    {
        char buffer[1024];
        ssize_t n = recv(_fd_array[who], buffer, sizeof(buffer) - 1, 0); 
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client# " << buffer << std::endl;
            // 把读到的信息，在回显会去
            std::string message = "echo# ";
            message += buffer;
            send(_fd_array[who], message.c_str(), message.size(), 0); 
        }
        else if (n == 0)
        {
            LOG(LogLevel::DEBUG) << "客户端退出, sockfd: " << _fd_array[who];
            close(_fd_array[who]);
            _fd_array[who] = gdefaultfd;
        }
        else
        {
            LOG(LogLevel::DEBUG) << "客户端读取出错, sockfd: " << _fd_array[who];
            close(_fd_array[who]);
            _fd_array[who] = gdefaultfd;
        }
    }
    void Dispatcher(fd_set& readfds)
    {
        for(int i = 0 ;i < NUM;i++)
        {
            if(_fd_array[i] == gdefaultfd)
                continue;
            // 两种情况：listen socket 或者 读文件描述符 就绪
            if(_fd_array[i] == _listen_socketfd->Fd())
            {
                if(FD_ISSET(_fd_array[i],&readfds))
                {
                    Accepter();
                }
            }
            else
            {
                if(FD_ISSET(_fd_array[i],&readfds))
                {
                    Recver(i);
                }
            }
        }
    }
public:
    SelectSever(uint16_t port):
        _port(port),
        _listen_socketfd(std::make_unique<TcpSocket>()),
        _running(false)
    {}
    void Init()
    {
        _listen_socketfd->BuildTcpSocketMethod(_port);
        for(int i = 0 ;i < NUM;i++)
            _fd_array[i] = gdefaultfd;
        
        // 将listen_sockfd添加到辅助数组中
        _fd_array[0] = _listen_socketfd->Fd();
    }
    void Loop()
    {
        _running = true;
        // 这里只是一个demo代码，所以只模拟了写入
        fd_set readfds;

        while(_running)
        {
            // 每次循环都要重新设置readfds
            FD_ZERO(&readfds);
            struct timeval timeout = {1,0};

            //找到最大的maxfd，并将需要关心的fd设置到readfds中
            int maxfd = gdefaultfd;
            for(int i = 0;i < NUM;i++)
            {
                if(_fd_array[i] == gdefaultfd)
                    continue;
                FD_SET(_fd_array[i],&readfds);

                if(_fd_array[i] > maxfd)
                    maxfd = _fd_array[i];
            }
            // 调用select等待
            int n = ::select(maxfd + 1,&readfds,nullptr,nullptr,&timeout);

            if(n < 0)
            {
                LOG(LogLevel::FATAL) << "select failed";
                break;
            }
            else if(n == 0)
            {
                LOG(LogLevel::ERROR) << "数据未就绪, timeout……";
            }
            else
            {
                LOG(LogLevel::DEBUG) << "事件已就绪……";
                Dispatcher(readfds);
            }
            sleep(1);
        }
        _running = false;
    }
    ~SelectSever()
    {}
private:
    uint16_t _port;
    std::unique_ptr<Socket> _listen_socketfd;
    bool _running;
    int _fd_array[NUM];
};

